home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / game / shoot / ADoomPPC_src.lha / ADoomPPC_src / amiga_net.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  36.5 KB  |  1,254 lines

  1.  
  2. #if defined(__SASC) && !defined(__VBCC__)
  3. #pragma options align=mac68k
  4. #endif
  5.  
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include <time.h>
  10.  
  11. #if defined(__SASC) && !defined(__VBCC__)
  12. #include <dos.h>
  13. #endif
  14.  
  15. #include <sys/socket.h>
  16. #include <netinet/in.h>
  17. #if !defined(MORPHOS) && !defined(__VBCC__)
  18. #include <arpa/inet.h>
  19. #endif
  20. #include <errno.h>
  21. #include <unistd.h>
  22. #include <netdb.h>
  23. #include <sys/ioctl.h>
  24.  
  25. #include <exec/exec.h>
  26. #include <devices/serial.h>
  27. #include <proto/exec.h>
  28.  
  29. #include <clib/alib_protos.h>
  30.  
  31. #if defined(__SASC) || defined(__VBCC__)
  32. #include <clib/socket_protos.h>
  33. #else
  34. #include <proto/socket.h>
  35. #endif
  36.  
  37. #ifdef AMIPX
  38. // These include file are distributed with amipx.library
  39. #include <libraries/amipx.h>
  40. #include <proto/amipx.h>
  41. #endif
  42.  
  43. #ifdef __SASC
  44. #pragma options align=power
  45. #endif
  46.  
  47. #include "i_system.h"
  48. #include "d_event.h"
  49. #include "d_net.h"
  50. #include "m_argv.h"
  51. #include "m_swap.h"
  52.  
  53. #include "doomstat.h"
  54.  
  55. #include "i_net.h"
  56.  
  57. extern struct ExecBase *SysBase;
  58.  
  59. #ifndef __VBCC__
  60. #define    BeginIO(ioRequest)    _BeginIO(ioRequest)
  61. extern void _BeginIO(struct IORequest *ioRequest);
  62. #endif
  63.  
  64. void cleanup_net (void);
  65.  
  66. extern void ppctimer (unsigned int *time);
  67. extern int bus_clock;
  68.  
  69. //
  70. // NETWORKING
  71. //
  72.  
  73. /**********************************************************************/
  74. /**********************************************************************/
  75. /* TCP/IP stuff */
  76.  
  77. struct Library *SocketBase = NULL;
  78.  
  79. static int IP_DOOMPORT = (IPPORT_USERRESERVED + 0x1d);
  80.  
  81. static int IP_sendsocket = -1;
  82. static int IP_insocket = -1;
  83.  
  84. static struct sockaddr_in IP_sendaddress[MAXNETNODES];
  85.  
  86. static void (*netget) (void);
  87. static void (*netsend) (void);
  88.  
  89.  
  90. /**********************************************************************/
  91. //
  92. // IP_UDPsocket
  93. //
  94. static int IP_UDPsocket (void)
  95. {
  96.   int s;
  97.  
  98.   // allocate a socket
  99.   s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  100.   if (s < 0)
  101.     I_Error ("can't create socket: %s", strerror(errno));
  102.   return s;
  103. }
  104.  
  105. /**********************************************************************/
  106. //
  107. // IP_BindToLocalPort
  108. //
  109. static void IP_BindToLocalPort (int s, int port)
  110. {
  111.   int v;
  112.   struct sockaddr_in address;
  113.  
  114.   memset (&address, 0, sizeof(address));
  115.   address.sin_family = AF_INET;
  116.   address.sin_addr.s_addr = INADDR_ANY;
  117.   address.sin_port = port;
  118.  
  119.   v = bind (s, (void *)&address, sizeof(address));
  120.   if (v == -1)
  121.     I_Error ("BindToPort: bind: %s", strerror(errno));
  122. }
  123.  
  124.  
  125. /**********************************************************************/
  126. //
  127. // IP_PacketSend
  128. //
  129. static void IP_PacketSend (void)
  130. {
  131.   int  c;
  132.   doomdata_t sw;
  133.  
  134.   // byte swap
  135.   sw.checksum = htonl(netbuffer->checksum);
  136.   sw.player = netbuffer->player;
  137.   sw.retransmitfrom = netbuffer->retransmitfrom;
  138.   sw.starttic = netbuffer->starttic;
  139.   sw.numtics = netbuffer->numtics;
  140.   for (c = 0 ; c < netbuffer->numtics; c++) {
  141.     sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  142.     sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  143.     sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
  144.     sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
  145.     sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  146.     sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  147.   }
  148.  
  149.   //printf ("sending %i\n",gametic);
  150.   c = sendto (IP_sendsocket , (UBYTE *)&sw, doomcom->datalength,
  151.               0, (void *)&IP_sendaddress[doomcom->remotenode],
  152.               sizeof(IP_sendaddress[doomcom->remotenode]));
  153. //  if (c == -1)
  154. //    /* why does AmiTCP 4.3 return EINVAL or ENOENT instead of EWOULDBLOCK ??? */
  155. //    if (errno != EWOULDBLOCK)
  156. //      I_Error ("SendPacket error: %s",strerror(errno));
  157. }
  158.  
  159.  
  160. /**********************************************************************/
  161. //
  162. // IP_PacketGet
  163. //
  164. static void IP_PacketGet (void)
  165. {
  166.   int i, c;
  167.   struct sockaddr_in fromaddress;
  168.   LONG fromlen;
  169.   doomdata_t sw;
  170.  
  171.   fromlen = sizeof(fromaddress);
  172.   c = recvfrom (IP_insocket, (UBYTE *)&sw, sizeof(sw), 0,
  173.                 (struct sockaddr *)&fromaddress, &fromlen);
  174.   if (c == -1) {
  175.     /* why does AmiTCP 4.3 return EINVAL or ENOENT instead of EWOULDBLOCK ??? */
  176. //    if (errno != EWOULDBLOCK)
  177. //      I_Error ("GetPacket: %s",strerror(errno));
  178.     doomcom->remotenode = -1;  // no packet
  179.     return;
  180.   }
  181.  
  182.   {
  183.     static int first=1;
  184.     if (first)
  185.       printf("len=%d:p=[0x%x 0x%x] \n", c, *(int*)&sw, *((int*)&sw+1));
  186.     first = 0;
  187.   }
  188.  
  189.   // find remote node number
  190.   for (i = 0; i < doomcom->numnodes; i++)
  191.     if (fromaddress.sin_addr.s_addr == IP_sendaddress[i].sin_addr.s_addr)
  192.       break;
  193.  
  194.   if (i == doomcom->numnodes) {
  195.     // packet is not from one of the players (new game broadcast)
  196.     doomcom->remotenode = -1;  // no packet
  197.     return;
  198.   }
  199.  
  200.   doomcom->remotenode = i;   // good packet from a game player
  201.   doomcom->datalength = c;
  202.  
  203.   // byte swap
  204.   netbuffer->checksum = ntohl(sw.checksum);
  205.   netbuffer->player = sw.player;
  206.   netbuffer->retransmitfrom = sw.retransmitfrom;
  207.   netbuffer->starttic = sw.starttic;
  208.   netbuffer->numtics = sw.numtics;
  209.  
  210.   for (c = 0; c < netbuffer->numtics; c++) {
  211.     netbuffer->cmds[c].forwardmove = sw.cmds[c].forwardmove;
  212.     netbuffer->cmds[c].sidemove = sw.cmds[c].sidemove;
  213.     netbuffer->cmds[c].angleturn = ntohs(sw.cmds[c].angleturn);
  214.     netbuffer->cmds[c].consistancy = ntohs(sw.cmds[c].consistancy);
  215.     netbuffer->cmds[c].chatchar = sw.cmds[c].chatchar;
  216.     netbuffer->cmds[c].buttons = sw.cmds[c].buttons;
  217.   }
  218. }
  219.  
  220.  
  221. /**********************************************************************/
  222. #if 0
  223. static int IP_GetLocalAddress (void)
  224. {
  225.   char hostname[1024];
  226.   struct hostent* hostentry; // host information entry
  227.   int v;
  228.  
  229.   // get local address
  230.   v = gethostname (hostname, sizeof(hostname));
  231.   if (v == -1)
  232.     I_Error ("IP_GetLocalAddress : gethostname: errno %d",errno);
  233.  
  234.   hostentry = gethostbyname (hostname);
  235.   if (!hostentry)
  236.     I_Error ("IP_GetLocalAddress : gethostbyname: couldn't get local host");
  237.  
  238.   return *(int *)hostentry->h_addr_list[0];
  239. }
  240. #endif
  241.  
  242. /**********************************************************************/
  243. //
  244. // IP_InitNetwork
  245. //
  246. static void IP_InitNetwork (int i)
  247. {
  248.   char trueval = true;
  249.   struct hostent* hostentry; // host information entry
  250.  
  251.   if ((SocketBase = OpenLibrary ("bsdsocket.library", 0)) == NULL)
  252.     I_Error ("OpenLibrary(\"bsdsocket.library\") failed");
  253.  
  254.   netsend = IP_PacketSend;
  255.   netget = IP_PacketGet;
  256.   netgame = true;
  257.  
  258.   // parse player number and host list
  259.   doomcom->consoleplayer = myargv[i+1][0]-'1';
  260.  
  261.   doomcom->numnodes = 1; // this node for sure
  262.  
  263.   i++;
  264.   while (++i < myargc && myargv[i][0] != '-') {
  265.     IP_sendaddress[doomcom->numnodes].sin_family = AF_INET;
  266.     IP_sendaddress[doomcom->numnodes].sin_port = htons(IP_DOOMPORT);
  267.     if (myargv[i][0] == '.') {
  268.       IP_sendaddress[doomcom->numnodes].sin_addr.s_addr = inet_addr (myargv[i]+1);
  269.     } else {
  270.       hostentry = gethostbyname (myargv[i]);
  271.       if (!hostentry)
  272.         I_Error ("gethostbyname: couldn't find %s", myargv[i]);
  273.       IP_sendaddress[doomcom->numnodes].sin_addr.s_addr =
  274.                                               *(int *)hostentry->h_addr_list[0];
  275.     }
  276.     doomcom->numnodes++;
  277.   }
  278.  
  279.   doomcom->id = DOOMCOM_ID;
  280.   doomcom->numplayers = doomcom->numnodes;
  281.  
  282.   // build message to receive
  283.   IP_insocket = IP_UDPsocket ();
  284.   IP_sendsocket = IP_UDPsocket ();
  285.  
  286.   IP_BindToLocalPort (IP_insocket, htons(IP_DOOMPORT));
  287.  
  288.   /* set both sockets to non-blocking */
  289.   if (IoctlSocket (IP_insocket, FIONBIO, &trueval) == -1 ||
  290.       IoctlSocket (IP_sendsocket, FIONBIO, &trueval) == -1)
  291.     I_Error ("IoctlSocket() failed: %s", strerror(errno));
  292. }
  293.  
  294. /**********************************************************************/
  295. static void IP_Shutdown (void)
  296. {
  297.   if (IP_insocket != -1) {
  298.     CloseSocket (IP_insocket);
  299.     IP_insocket = -1;
  300.   }
  301.   if (IP_sendsocket != -1) {
  302.     CloseSocket (IP_sendsocket);
  303.     IP_sendsocket = -1;
  304.   }
  305.   if (SocketBase != NULL) {
  306.     CloseLibrary (SocketBase);
  307.     SocketBase = NULL;
  308.   }
  309. }
  310.  
  311. /**********************************************************************/
  312. /**********************************************************************/
  313. /* experimental low level serial port stuff */
  314.  
  315. static struct MsgPort *SER_writelen_mp = NULL;
  316. static struct MsgPort *SER_readlen_mp = NULL;
  317. static struct MsgPort *SER_write_mp = NULL;
  318. static struct MsgPort *SER_read_mp = NULL;
  319. static struct IOExtSer *SER_writelen_io = NULL;
  320. static struct IOExtSer *SER_readlen_io = NULL;
  321. static struct IOExtSer *SER_write_io = NULL;
  322. static struct IOExtSer *SER_read_io = NULL;
  323. static BOOL SER_is_open = FALSE;
  324. static BOOL SER_write_in_progress = FALSE;
  325. static BOOL SER_read_in_progress = FALSE;
  326. static BOOL SER_readlen_in_progress = FALSE;
  327. static BOOL SER_read_waiting_for_len;
  328. static UBYTE SER_get_len, SER_get_len2;
  329. static doomdata_t SER_get_sw;
  330.  
  331. /**********************************************************************/
  332. //
  333. // SER_PacketSend
  334. //
  335. static void SER_PacketSend (void)
  336. {
  337.   int  c;
  338.   static doomdata_t sw;
  339.   static UBYTE len;
  340.  
  341.   if (SER_write_in_progress) {
  342.  
  343. //    if (!CheckIO ((struct IORequest *)SER_write_io))
  344. //      return;       /* previous write hasn't finished yet, forget it */
  345.  
  346.     WaitIO ((struct IORequest *)SER_writelen_io);
  347.     WaitIO ((struct IORequest *)SER_write_io);
  348.     SER_write_in_progress = FALSE;
  349.   }
  350.  
  351.   // byte swap
  352.   sw.checksum = htonl(netbuffer->checksum);
  353.   sw.player = netbuffer->player;
  354.   sw.retransmitfrom = netbuffer->retransmitfrom;
  355.   sw.starttic = netbuffer->starttic;
  356.   sw.numtics = netbuffer->numtics;
  357.   for (c = 0 ; c < netbuffer->numtics; c++) {
  358.     sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  359.     sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  360.     sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
  361.     sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
  362.     sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  363.     sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  364.   }
  365.  
  366.   len = doomcom->datalength;
  367.  
  368.   if (len > 0) {
  369.  
  370. //    printf ("Sending len = %d  %08x %08x ...\n", len, ((ULONG *)&sw)[0],
  371. //            ((ULONG *)&sw)[1]);
  372.  
  373.     SER_writelen_io->IOSer.io_Length = 1;
  374.     SER_writelen_io->IOSer.io_Data = &len;
  375.     SER_writelen_io->IOSer.io_Command = CMD_WRITE;
  376.     SER_writelen_io->IOSer.io_Flags |= IOF_QUICK;
  377.     BeginIO ((struct IORequest *)SER_writelen_io);
  378.  
  379.     SER_write_io->IOSer.io_Length = len;
  380.     SER_write_io->IOSer.io_Data = (UBYTE *)&sw;
  381.     SER_write_io->IOSer.io_Command = CMD_WRITE;
  382.     SER_write_io->IOSer.io_Flags |= IOF_QUICK;
  383.     BeginIO ((struct IORequest *)SER_write_io);
  384.  
  385.     SER_write_in_progress = TRUE;
  386.  
  387.   }
  388. }
  389.  
  390. /**********************************************************************/
  391. //
  392. // SER_PacketGet
  393. //
  394. static void SER_PacketGet (void)
  395. {
  396.   int c;
  397.  
  398.   if (SER_read_waiting_for_len) {
  399.  
  400.     if (!CheckIO ((struct IORequest *)SER_readlen_io)) {
  401.       doomcom->remotenode = -1;  // no packet
  402.       return;
  403.     }
  404.  
  405.     WaitIO ((struct IORequest *)SER_readlen_io);/* should return immediately */
  406.     SER_readlen_in_progress = FALSE;
  407.  
  408.     SER_get_len2 = SER_get_len;
  409.  
  410.     if (SER_get_len2 != 0) {
  411.  
  412. //      printf ("Receiving len = %d, lenstatus = %d", (int)SER_get_len2,
  413. //              SER_readlen_io->IOSer.io_Error);
  414.  
  415.       SER_read_io->IOSer.io_Length = SER_get_len2;
  416.       SER_read_io->IOSer.io_Data = (UBYTE *)&SER_get_sw;
  417.       SER_read_io->IOSer.io_Command = CMD_READ;
  418.       SER_read_io->IOSer.io_Flags |= IOF_QUICK;
  419.       BeginIO ((struct IORequest *)SER_read_io);
  420.       SER_read_in_progress = TRUE;
  421.  
  422.       SER_read_waiting_for_len = FALSE;
  423.  
  424.     }
  425.     SER_readlen_io->IOSer.io_Length = 1;
  426.     SER_readlen_io->IOSer.io_Data = &SER_get_len;
  427.     SER_readlen_io->IOSer.io_Command = CMD_READ;
  428.     SER_readlen_io->IOSer.io_Flags |= IOF_QUICK;
  429.     BeginIO ((struct IORequest *)SER_readlen_io);
  430.     SER_readlen_in_progress = TRUE;
  431.  
  432.     doomcom->remotenode = -1;  // no packet
  433.     return;
  434.   }
  435.  
  436.   if (SER_read_in_progress)
  437.     if (!CheckIO ((struct IORequest *)SER_read_io)) {
  438.       doomcom->remotenode = -1;  // no packet
  439.       return;
  440.     }
  441.  
  442.   WaitIO ((struct IORequest *)SER_read_io); /* should return immediately */
  443.   SER_read_in_progress = FALSE;
  444.  
  445. //  printf (", status = %d  %08x %08x ...\n", SER_read_io->IOSer.io_Error,
  446. //          ((ULONG *)&SER_get_sw)[0], ((ULONG *)&SER_get_sw)[1]);
  447.  
  448.   {
  449.     static int first=1;
  450.     if (first)
  451.       printf("len=%d:p=[0x%x 0x%x] \n", SER_get_len2, *(int*)&SER_get_sw,
  452.              *((int*)&SER_get_sw+1));
  453.     first = 0;
  454.   }
  455.  
  456.   doomcom->remotenode = 1;  /* from the other player */
  457.   doomcom->datalength = SER_get_len2;
  458.  
  459.   // byte swap
  460.   netbuffer->checksum = ntohl(SER_get_sw.checksum);
  461.   netbuffer->player = SER_get_sw.player;
  462.   netbuffer->retransmitfrom = SER_get_sw.retransmitfrom;
  463.   netbuffer->starttic = SER_get_sw.starttic;
  464.   netbuffer->numtics = SER_get_sw.numtics;
  465.  
  466.   for (c = 0; c < netbuffer->numtics; c++) {
  467.     netbuffer->cmds[c].forwardmove = SER_get_sw.cmds[c].forwardmove;
  468.     netbuffer->cmds[c].sidemove = SER_get_sw.cmds[c].sidemove;
  469.     netbuffer->cmds[c].angleturn = ntohs(SER_get_sw.cmds[c].angleturn);
  470.     netbuffer->cmds[c].consistancy = ntohs(SER_get_sw.cmds[c].consistancy);
  471.     netbuffer->cmds[c].chatchar = SER_get_sw.cmds[c].chatchar;
  472.     netbuffer->cmds[c].buttons = SER_get_sw.cmds[c].buttons;
  473.   }
  474.  
  475.   SER_read_waiting_for_len = TRUE;
  476. }
  477.  
  478. /**********************************************************************/
  479. //
  480. // SER_InitNetwork
  481. //
  482. void SER_InitNetwork (int i)
  483. {
  484.   int unit, speed;
  485.  
  486.   netsend = SER_PacketSend;
  487.   netget = SER_PacketGet;
  488.   netgame = true;
  489.  
  490.   // parse player number and host list
  491.   doomcom->consoleplayer = myargv[i+1][0]-'1';
  492.  
  493.   doomcom->numnodes = 2;
  494.   doomcom->id = DOOMCOM_ID;
  495.   doomcom->numplayers = doomcom->numnodes;
  496.  
  497.   if ((SER_writelen_mp = CreateMsgPort ()) == NULL ||
  498.       (SER_readlen_mp = CreateMsgPort ()) == NULL ||
  499.       (SER_write_mp = CreateMsgPort ()) == NULL ||
  500.       (SER_read_mp = CreateMsgPort ()) == NULL ||
  501.       (SER_writelen_io = (struct IOExtSer *)CreateIORequest (SER_writelen_mp,
  502.                                             sizeof(struct IOExtSer))) == NULL ||
  503.       (SER_readlen_io = (struct IOExtSer *)CreateIORequest (SER_readlen_mp,
  504.                                             sizeof(struct IOExtSer))) == NULL ||
  505.       (SER_write_io = (struct IOExtSer *)CreateIORequest (SER_write_mp,
  506.                                             sizeof(struct IOExtSer))) == NULL ||
  507.       (SER_read_io = (struct IOExtSer *)CreateIORequest (SER_read_mp,
  508.                                             sizeof(struct IOExtSer))) == NULL)
  509.     I_Error ("Can't create port");
  510.  
  511.   unit = atoi(myargv[i+3]);
  512.   speed = atoi(myargv[i+4]);
  513.  
  514.   SER_write_io->io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  515.  
  516.   if (OpenDevice (myargv[i+2], unit, (struct IORequest *)SER_write_io, 0) != 0)
  517.     I_Error ("Can't open %s port %d", myargv[i+2], unit);
  518.   SER_is_open = TRUE;
  519.  
  520.   SER_write_io->io_SerFlags &= ~SERF_PARTY_ON;
  521.   SER_write_io->io_SerFlags |= SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  522.   SER_write_io->io_Baud = speed;
  523.   SER_write_io->io_ReadLen = 8;
  524.   SER_write_io->io_WriteLen = 8;
  525.   SER_write_io->io_StopBits = 1;
  526.   SER_write_io->io_RBufLen = 65536;
  527.   SER_write_io->IOSer.io_Command = SDCMD_SETPARAMS;
  528.   if (DoIO ((struct IORequest *)SER_write_io) != 0)
  529.     I_Error ("Error setting serial parameters (speed = %d)", speed);
  530.  
  531.   CopyMem (SER_write_io, SER_read_io, sizeof(struct IOExtSer));
  532.   SER_read_io->IOSer.io_Message.mn_ReplyPort = SER_read_mp;
  533.  
  534.   CopyMem (SER_write_io, SER_readlen_io, sizeof(struct IOExtSer));
  535.   SER_readlen_io->IOSer.io_Message.mn_ReplyPort = SER_readlen_mp;
  536.  
  537.   CopyMem (SER_write_io, SER_writelen_io, sizeof(struct IOExtSer));
  538.   SER_writelen_io->IOSer.io_Message.mn_ReplyPort = SER_writelen_mp;
  539.  
  540.   SER_readlen_io->IOSer.io_Length = 1;
  541.   SER_readlen_io->IOSer.io_Data = &SER_get_len;
  542.   SER_readlen_io->IOSer.io_Command = CMD_READ;
  543.   SER_readlen_io->IOSer.io_Flags |= IOF_QUICK;
  544.   BeginIO ((struct IORequest *)SER_readlen_io);
  545.   SER_readlen_in_progress = TRUE;
  546.  
  547.   SER_read_waiting_for_len = TRUE;
  548.  
  549. }
  550.  
  551. /**********************************************************************/
  552. static void SER_Shutdown (void)
  553. {
  554.   if (SER_is_open) {
  555.     if (SER_readlen_in_progress) {
  556.       AbortIO ((struct IORequest *)SER_readlen_io);
  557.       WaitIO ((struct IORequest *)SER_readlen_io);
  558.       SER_readlen_in_progress = FALSE;
  559.     }
  560.     if (SER_read_in_progress) {
  561.       AbortIO ((struct IORequest *)SER_read_io);
  562.       WaitIO ((struct IORequest *)SER_read_io);
  563.       SER_read_in_progress = FALSE;
  564.     }
  565.     if (SER_write_in_progress) {
  566.       AbortIO ((struct IORequest *)SER_writelen_io);
  567.       WaitIO ((struct IORequest *)SER_writelen_io);
  568.       AbortIO ((struct IORequest *)SER_write_io);
  569.       WaitIO ((struct IORequest *)SER_write_io);
  570.       SER_write_in_progress = FALSE;
  571.     }
  572.     CloseDevice ((struct IORequest *)SER_write_io);
  573.     SER_is_open = FALSE;
  574.   }
  575.   if (SER_readlen_io != NULL) {
  576.     DeleteIORequest ((struct IORequest *)SER_readlen_io);
  577.     SER_readlen_io = NULL;
  578.   }
  579.   if (SER_readlen_mp != NULL) {
  580.     DeleteMsgPort (SER_readlen_mp);
  581.     SER_readlen_mp = NULL;
  582.   }
  583.   if (SER_writelen_io != NULL) {
  584.     DeleteIORequest ((struct IORequest *)SER_writelen_io);
  585.     SER_writelen_io = NULL;
  586.   }
  587.   if (SER_writelen_mp != NULL) {
  588.     DeleteMsgPort (SER_writelen_mp);
  589.     SER_writelen_mp = NULL;
  590.   }
  591.   if (SER_read_io != NULL) {
  592.     DeleteIORequest ((struct IORequest *)SER_read_io);
  593.     SER_read_io = NULL;
  594.   }
  595.   if (SER_read_mp != NULL) {
  596.     DeleteMsgPort (SER_read_mp);
  597.     SER_read_mp = NULL;
  598.   }
  599.   if (SER_write_io != NULL) {
  600.     DeleteIORequest ((struct IORequest *)SER_write_io);
  601.     SER_write_io = NULL;
  602.   }
  603.   if (SER_write_mp != NULL) {
  604.     DeleteMsgPort (SER_write_mp);
  605.     SER_write_mp = NULL;
  606.   }
  607. }
  608.  
  609. /**********************************************************************/
  610. /**********************************************************************/
  611.  
  612. #ifdef AMIPX
  613.  
  614. /**********************************************************************/
  615. /* experimental IPX stuff */
  616.  
  617. #define IPX_NUMPACKETS      10          // max outstanding packets before loss
  618.  
  619. #ifdef __SASC
  620. #pragma options align=mac68k
  621. #endif
  622.  
  623. // setupdata_t is used as doomdata_t during setup
  624. typedef struct
  625. {
  626.   WORD  gameid;      // so multiple games can setup at once
  627.   WORD  drone;       // You must take care to make gameid LSB first - GJP
  628.   WORD  nodesfound;  // these two are only compared to each other so it
  629.   WORD  nodeswanted; // does not matter what internal storage you use
  630. }  setupdata_t;
  631.  
  632. typedef struct {
  633.   UBYTE  network[4];             /* high-low */
  634.   UBYTE  node[6];                /* high-low */
  635. }  localadr_t;
  636.  
  637. typedef struct {
  638.   UBYTE  node[6];                /* high-low */
  639. }  nodeadr_t;
  640.  
  641. // I think a version I downloaded in late 1997, used just one fragment,
  642. // but multiple fragments is supported by AMIPX, I even endorse it - GJP 
  643.  
  644. // time is used by the communication driver to sequence packets returned
  645. // to DOOM when more than one is waiting
  646. // this is were the 68k has to be very careful to store the time LSB first- GJP
  647. typedef struct {
  648.   struct AMIPX_ECB  ecb;      /* too small!!!  need space for 2 fragments !!! */
  649.   struct AMIPX_Fragment  dummy;  /* maybe this will fix it */
  650.   struct AMIPX_PacketHeader  ipx;
  651.   long  time;
  652.   doomdata_t  data;
  653. }  packet_t;
  654.  
  655. #ifdef __SASC
  656. #pragma options align=power
  657. #endif
  658.  
  659. struct AMIPX_Library *AMIPX_Library = NULL;
  660. static packet_t IPX_packets[IPX_NUMPACKETS];
  661. static nodeadr_t IPX_nodeadr[MAXNETNODES+1];  // first is local, last is broadcast
  662. static nodeadr_t IPX_remoteadr;               // set by each GetPacket
  663. static localadr_t IPX_localadr;        // set at startup
  664. static UWORD IPX_socketid = 0;
  665. static long IPX_localtime;          // for time stamp in packets
  666. static long IPX_remotetime;
  667. static BOOL IPX_got_a_packet;
  668.  
  669. /**********************************************************************/
  670. static int IPX_OpenSocket (WORD socketNumber)
  671. {
  672.   int outsock;
  673.  
  674.   if ((outsock = AMIPX_OpenSocket (socketNumber)) == 0)
  675.     I_Error ("AMIPX_OpenSocket() failed");
  676.   return outsock;
  677. }
  678.  
  679. /**********************************************************************/
  680. static void IPX_ListenForPacket (struct AMIPX_ECB *ecb)
  681. {
  682.   int retval;
  683.  
  684.   if ((retval = AMIPX_ListenForPacket (ecb)))
  685.     I_Error ("ListenForPacket: 0x%x", retval);
  686. }
  687.  
  688. /**********************************************************************/
  689.  
  690. #if 0
  691.  
  692. static void print_address (char *msg, struct AMIPX_Address *adr)
  693. {
  694.   printf ("   %s Network:         %02x:%02x:%02x:%02x\n", msg,
  695.           adr->Network[0], adr->Network[1],
  696.           adr->Network[2], adr->Network[3]);
  697.   printf ("   %s Node:            %02x:%02x:%02x:%02x:%02x:%02x\n", msg,
  698.           adr->Node[0], adr->Node[1], adr->Node[2],
  699.           adr->Node[3], adr->Node[4], adr->Node[5]);
  700.   printf ("   %s Socket:          %04x\n", msg, adr->Socket);
  701. }
  702.  
  703. /**********************************************************************/
  704. static void print_ipx (struct AMIPX_PacketHeader *ipx)
  705. {
  706.   printf ("IPX Packet header at $%08x\n", ipx);
  707.   printf ("  Checksum:             %04x\n", ipx->Checksum);
  708.   printf ("  Length:               %04x\n", ipx->Length);
  709.   printf ("  Tc:                   %02x\n", ipx->Tc);
  710.   printf ("  Type:                 %02x\n", ipx->Type);
  711.   print_address ("Dst", &ipx->Dst);
  712.   print_address ("Src", &ipx->Src);
  713. }
  714.  
  715. /**********************************************************************/
  716. static void print_ecb (struct AMIPX_ECB *ecb)
  717. {
  718.   int i;
  719.  
  720.   printf ("ECB   at $%08x\n", ecb);
  721.   printf ("  Link:                 %08x\n", ecb->Link);
  722.   printf ("  ESR:                  %08x\n", ecb->ESR);
  723.   printf ("  InUse:                %02x\n", ecb->InUse);
  724.   printf ("  CompletionCode:       %02x\n", ecb->CompletionCode);
  725.   printf ("  Socket:               %04x\n", ecb->Socket);
  726.   printf ("  IPXWork:              %02x:%02x:%02x:%02x\n",
  727.           ecb->IPXWork[0], ecb->IPXWork[1],
  728.           ecb->IPXWork[2], ecb->IPXWork[3]);
  729.   printf ("  ImmedAddr:            %02x:%02x:%02x:%02x:%02x:%02x\n",
  730.           ecb->ImmedAddr[0], ecb->ImmedAddr[1],
  731.           ecb->ImmedAddr[2], ecb->ImmedAddr[3],
  732.           ecb->ImmedAddr[4], ecb->ImmedAddr[5]);
  733.   printf ("  FragCount:            %04x\n", ecb->FragCount);
  734.   for (i = 0; i < ecb->FragCount; i++) {
  735.     printf ("  Fragment[%d].FragData: %08x\n", i, ecb->Fragment[i].FragData);
  736.     printf ("  Fragment[%d].FragSize: %04x\n", i,
  737.             ecb->Fragment[i].FragSize);
  738.   }
  739. }
  740.  
  741. #endif
  742.  
  743. /**********************************************************************/
  744. // Send the data defined by doomcom->data and doomcom->datalength
  745. // to the node doomcom->remotenode.
  746. // Broadcast if doomcom->remotenode == MAXNETNODES
  747.  
  748. static void IPX_PacketSend (void)
  749. {
  750.   int j, c, retval;
  751.   int destination;
  752.   int len;
  753.   doomdata_t sw;
  754.  
  755.   // byte swap if not in setup
  756.   if (IPX_localtime != -1) {
  757.     sw.checksum = SWAPLONG(netbuffer->checksum);
  758.     sw.player = netbuffer->player;
  759.     sw.retransmitfrom = netbuffer->retransmitfrom;
  760.     sw.starttic = netbuffer->starttic;
  761.     sw.numtics = netbuffer->numtics;
  762.  
  763.     for (c = 0 ; c < netbuffer->numtics; c++) {
  764.       sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  765.       sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  766.       sw.cmds[c].angleturn = SWAPSHORT(netbuffer->cmds[c].angleturn);
  767.       sw.cmds[c].consistancy = SWAPSHORT(netbuffer->cmds[c].consistancy);
  768.       sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  769.       sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  770.     }
  771.     IPX_packets[0].ecb.Fragment[1].FragData = (UBYTE *)&sw;
  772.   } else
  773.     IPX_packets[0].ecb.Fragment[1].FragData = (UBYTE *)&doomcom->data;
  774.  
  775.   destination = doomcom->remotenode;
  776.  
  777. // set the time
  778.   IPX_packets[0].time = SWAPLONG(IPX_localtime); // Amiga puts MSB first
  779.  
  780. // set the address
  781.   for (j = 0; j < 6; j++)
  782.     IPX_packets[0].ipx.Dst.Node[j] = IPX_packets[0].ecb.ImmedAddr[j]
  783.                                    = IPX_nodeadr[destination].node[j];
  784.  
  785. // set the length (ipx + time + datalength)
  786.   len = sizeof(struct AMIPX_PacketHeader) + sizeof(long) + doomcom->datalength
  787.         + 4;
  788.   IPX_packets[0].ipx.Checksum = 0xffff;
  789.   IPX_packets[0].ipx.Length = len;
  790.   IPX_packets[0].ipx.Type = 4;
  791.   IPX_packets[0].ecb.Fragment[0].FragSize = sizeof(struct AMIPX_PacketHeader)
  792.                                             + sizeof(long);
  793.   IPX_packets[0].ecb.Fragment[1].FragSize = doomcom->datalength + 4;
  794.  
  795. // send the packet
  796. /*
  797.   printf ("Sending ");
  798.   print_ecb (&(IPX_packets[0].ecb));
  799.   printf ("with IPX header ");
  800.   print_ipx ((struct AMIPX_PacketHeader *)
  801.              IPX_packets[0].ecb.Fragment[0].FragData);
  802. */
  803.   if ((retval = AMIPX_SendPacket (&(IPX_packets[0].ecb))) != 0)
  804.     I_Error ("SendPacket: 0x%x", retval);
  805.  
  806.   while(IPX_packets[0].ecb.InUse != 0) {
  807. // IPX Relinquish Control - polled drivers MUST have this here!
  808.     AMIPX_RelinquishControl ();
  809.   }
  810. }
  811.  
  812. /**********************************************************************/
  813. // If there are no packets to receive, set IPX_got_a_packet = FALSE,
  814. //   and doomcom->remotenode = -1.
  815. // Otherwise set IPX_got_a_packet to TRUE and return packet in
  816. //   doomcom->data and doomcom->datalen.
  817. // Set IPX_remoteadr to address of remote node.
  818. // If we know who it came from, set doomcom->remotenode accordingly,
  819. //   otherwise set doomcom->remotenode = -1.
  820.  
  821. static void IPX_PacketGet (void)
  822. {
  823.   int packetnum;
  824.   int i, c;
  825.   long besttic;
  826.   packet_t *packet;
  827.   doomdata_t *sw;
  828.  
  829. // if multiple packets are waiting, return them in order by time
  830.  
  831.   IPX_got_a_packet = FALSE;
  832.   besttic = MAXLONG;
  833.   packetnum = -1;
  834.   doomcom->remotenode = -1;
  835.  
  836.   /* printf ("Looking for received packets...\n"); */
  837.  
  838.   for (i = 1; i < IPX_NUMPACKETS; i++)
  839.     if (!IPX_packets[i].ecb.InUse) {
  840.  
  841.       /* printf ("\nGOT A PACKET!!!\n"); */
  842.  
  843.       if ((IPX_localtime != -1 && IPX_packets[i].time == -1))
  844.         IPX_ListenForPacket (&IPX_packets[i].ecb); // unwanted packet
  845.       else if (SWAPLONG(IPX_packets[i].time) < besttic) {
  846.         besttic = SWAPLONG(IPX_packets[i].time);
  847.         packetnum = i;
  848.       }
  849.     }
  850.  
  851.   if (besttic == MAXLONG)
  852.     return;                           // no packets
  853.  
  854. //
  855. // got a good packet
  856. //
  857.   IPX_got_a_packet = TRUE;
  858.   packet = &IPX_packets[packetnum];
  859.   IPX_remotetime = besttic;
  860.  
  861.   if (packet->ecb.CompletionCode)
  862.     I_Error ("IPX_PacketGet: ecb.CompletionCode = 0x%x",
  863.              packet->ecb.CompletionCode);
  864. // corrected that ancient typo, sorry - GJP
  865. // set IPX_remoteadr to the sender of the packet
  866.   memcpy (&IPX_remoteadr, packet->ipx.Src.Node, sizeof(IPX_remoteadr));
  867.   for (i = 0; i < doomcom->numnodes; i++)
  868.     if (!memcmp(&IPX_remoteadr, &IPX_nodeadr[i], sizeof(IPX_remoteadr)))
  869.       break;
  870.   if (i < doomcom->numnodes)
  871.     doomcom->remotenode = i;
  872.   else {
  873.     if (IPX_localtime != -1) {    // this really shouldn't happen
  874.       IPX_ListenForPacket (&packet->ecb);
  875.       return;
  876.     }
  877.   }
  878.  
  879. // copy out the data
  880.   doomcom->datalength = packet->ipx.Length - sizeof(struct AMIPX_PacketHeader)
  881.                         - sizeof(long) - 4;
  882.   // byte swap if not in setup time
  883.   if (IPX_localtime != -1) {
  884.     sw = &packet->data;
  885.     netbuffer->checksum = SWAPLONG(sw->checksum);
  886.     netbuffer->player = sw->player;
  887.     netbuffer->retransmitfrom = sw->retransmitfrom;
  888.     netbuffer->starttic = sw->starttic;
  889.     netbuffer->numtics = sw->numtics;
  890.  
  891.     for (c = 0; c < netbuffer->numtics; c++) {
  892.       netbuffer->cmds[c].forwardmove = sw->cmds[c].forwardmove;
  893.       netbuffer->cmds[c].sidemove = sw->cmds[c].sidemove;
  894.       netbuffer->cmds[c].angleturn = SWAPSHORT(sw->cmds[c].angleturn);
  895.       netbuffer->cmds[c].consistancy = SWAPSHORT(sw->cmds[c].consistancy);
  896.       netbuffer->cmds[c].chatchar = sw->cmds[c].chatchar;
  897.       netbuffer->cmds[c].buttons = sw->cmds[c].buttons;
  898.     }
  899.   } else
  900.     memcpy (&doomcom->data, &packet->data, doomcom->datalength);
  901.  
  902. // repost the ECB
  903.   IPX_ListenForPacket (&packet->ecb);
  904. }
  905.  
  906. /**********************************************************************/
  907. static void IPX_LookForNodes (int numnetnodes)
  908. {
  909.   int i;
  910.   unsigned int clock[2];
  911.   int oldsec;
  912.   int currsec;
  913.   setupdata_t *dest;
  914.   int total, console;
  915.   static setupdata_t nodesetup[MAXNETNODES];
  916.  
  917. //
  918. // wait until we get [numnetnodes] packets, then start playing
  919. // the playernumbers are assigned by netid
  920. //
  921.   printf ("Attempting to find all players for %i player net play. "
  922.           "Press CTRL/C to exit.\n", numnetnodes);
  923.  
  924.   printf ("Looking for a node...\n");
  925.  
  926.   oldsec = -1;
  927.   IPX_localtime = -1;          // in setup time, not game time
  928.  
  929. //
  930. // build local setup info
  931. //
  932.   nodesetup[0].nodesfound = 1;
  933.   nodesetup[0].nodeswanted = numnetnodes;
  934.   doomcom->numnodes = 1;
  935.  
  936.   for (;;) {
  937.     //
  938.     // check for aborting
  939.     //
  940. #if defined(__SASC) && !defined(__VBCC__)
  941.     chkabort ();
  942. #endif
  943.     //
  944.     // listen to the network
  945.     //
  946.     for (;;) {
  947.  
  948.       IPX_PacketGet ();
  949.  
  950.       if (!IPX_got_a_packet)
  951.         break;
  952.  
  953.       if (doomcom->remotenode == -1) {     // it's from a new address
  954.         dest = &nodesetup[doomcom->numnodes];
  955.       } else {                        // it's from a node we already know about
  956.         dest = &nodesetup[doomcom->remotenode];
  957.       }
  958.  
  959.       if (IPX_remotetime != -1) {   // an early game packet, not a setup packet
  960.         if (doomcom->remotenode == -1)
  961.           I_Error ("Got an unknown game packet during setup");
  962.         // if it allready started, it must have found all nodes
  963.         dest->nodesfound = dest->nodeswanted;  // both swapped
  964.         continue;
  965.       }
  966.  
  967.       // update setup info
  968.       memcpy (dest, &doomcom->data, sizeof(*dest));
  969.  
  970.       if (doomcom->remotenode == -1) {     // it's from a new address
  971.  
  972.         memcpy (&IPX_nodeadr[doomcom->numnodes], &IPX_remoteadr,
  973.                 sizeof(IPX_nodeadr[doomcom->numnodes]));
  974.         //
  975.         // if this node has a lower address, take all startup info
  976.         //
  977.         if (memcmp(&IPX_remoteadr, &IPX_nodeadr[0], sizeof(&IPX_remoteadr))
  978.                                                                          < 0) {
  979.         }  // No action ?!
  980.            // You could call this a bug - how does one DOOM know
  981.            // whether everyone wants the same number of players?
  982.            // However, because of this, using internal storage for
  983.            // these setup packets actually works.
  984.            // (which saves the Mac version, because if this was not
  985.            // ignored, the PC would start looking for a multiple of
  986.            // 256 players) - GJP
  987.  
  988.         doomcom->numnodes++;
  989.  
  990.         printf ("\nFound node [%02x:%02x:%02x:%02x:%02x:%02x]\n",
  991.                 IPX_remoteadr.node[0], IPX_remoteadr.node[1],
  992.                 IPX_remoteadr.node[2], IPX_remoteadr.node[3],
  993.                 IPX_remoteadr.node[4], IPX_remoteadr.node[5]);
  994.  
  995.         if (doomcom->numnodes < numnetnodes)
  996.           printf ("Looking for a node...\n");
  997.  
  998.       } /* end if (doomcom->remotenode == -1) */
  999.  
  1000.     } /* end for (;;) until no more packets received */
  1001.  
  1002.     //
  1003.     // we are done if all nodes have found all other nodes
  1004.     //
  1005.     for (i = 0; i < doomcom->numnodes; i++)
  1006.       if (nodesetup[i].nodesfound != nodesetup[i].nodeswanted) // both swapped
  1007.         break;
  1008.  
  1009.     // You will notice that nodesetup[0].nodesfound is never compared to
  1010.     // nodesetup[i].nodeswanted  
  1011.     if (i == nodesetup[0].nodeswanted)
  1012.       break;         // got them all
  1013.  
  1014.     //
  1015.     // send out a broadcast packet every second
  1016.     //
  1017.     ppctimer (clock);
  1018.     currsec = (clock[1] / (bus_clock>>2));
  1019.     if (currsec != oldsec) {
  1020.       oldsec = currsec;
  1021.  
  1022.       printf (".");
  1023.       fflush (stdout);
  1024.  
  1025.       nodesetup[0].nodesfound = doomcom->numnodes;
  1026.       memcpy (&doomcom->data, &nodesetup[0], sizeof(setupdata_t));
  1027.       doomcom->remotenode = MAXNETNODES;
  1028.       doomcom->datalength = sizeof(setupdata_t);
  1029.       IPX_PacketSend ();     // send to all
  1030.     }
  1031.  
  1032.   } /* end for (;;) until all nodes have found all other nodes */
  1033.  
  1034. //
  1035. // count players
  1036. //
  1037.   total = 0;
  1038.   console = 0;
  1039.  
  1040.   for (i = 0; i < numnetnodes; i++) {
  1041.     if (nodesetup[i].drone)
  1042.       continue;
  1043.     total++;
  1044.     if (total > MAXPLAYERS)
  1045.       I_Error ("More than %i players specified!", MAXPLAYERS);
  1046.     if (M_CheckParm ("-reverseipx")) {
  1047.       if (memcmp (&IPX_nodeadr[i], &IPX_nodeadr[0], sizeof(IPX_nodeadr[0])) > 0)
  1048.         console++;
  1049.     } else {
  1050.       if (memcmp (&IPX_nodeadr[i], &IPX_nodeadr[0], sizeof(IPX_nodeadr[0])) < 0)
  1051.         console++;
  1052.     }
  1053.   }
  1054.  
  1055.   if (!total)
  1056.     I_Error ("No players specified for game!");
  1057.  
  1058.   doomcom->consoleplayer = console;
  1059.   doomcom->numplayers = total;
  1060.  
  1061.   printf ("Console is player %i of %i\n", console+1, total);
  1062. }
  1063.  
  1064. /**********************************************************************/
  1065. void IPX_InitNetwork (int p)
  1066. {
  1067.   int i, socket;
  1068.  
  1069. //
  1070. // get IPX function address
  1071. //
  1072.   if ((AMIPX_Library = (struct AMIPX_Library *)OpenLibrary
  1073.                                                  ("amipx.library",0L)) == NULL)
  1074.     I_Error ("Can't open amipx.library");
  1075.  
  1076. //
  1077. // allocate a socket for sending and receiving
  1078. //
  1079.   socket = 0x869b;
  1080.   i = M_CheckParm ("-socket");
  1081.   if (i && i < myargc - 1) {
  1082.     socket = atoi (myargv[i+1]);
  1083.   }
  1084.   IPX_socketid = IPX_OpenSocket (socket);
  1085.   printf ("Using IPX socket 0x%04x\n", IPX_socketid);
  1086.  
  1087.   AMIPX_GetLocalAddr ((BYTE *)&IPX_localadr);
  1088.   printf ("Local address is [%02x:%02x:%02x:%02x:%02x:%02x]\n",
  1089.           IPX_localadr.node[0], IPX_localadr.node[1], IPX_localadr.node[2],
  1090.           IPX_localadr.node[3], IPX_localadr.node[4], IPX_localadr.node[5]);
  1091.  
  1092. //
  1093. // set up several receiving ECBs
  1094. //
  1095.   memset (IPX_packets, 0, IPX_NUMPACKETS * sizeof(packet_t));
  1096.  
  1097.   for (i = 1; i < IPX_NUMPACKETS; i++) {
  1098.     IPX_packets[i].ecb.Socket = IPX_socketid;
  1099.     IPX_packets[i].ecb.FragCount = 2;
  1100.     IPX_packets[i].ecb.Fragment[0].FragData = (BYTE *)&IPX_packets[i].ipx;
  1101.     IPX_packets[i].ecb.Fragment[0].FragSize = sizeof(struct AMIPX_PacketHeader)
  1102.                                             + sizeof(long);
  1103.     IPX_packets[i].ecb.Fragment[1].FragData = (BYTE *)&IPX_packets[i].data;
  1104.     IPX_packets[i].ecb.Fragment[1].FragSize = sizeof(doomdata_t);
  1105.     IPX_ListenForPacket (&IPX_packets[i].ecb);
  1106.   }
  1107.  
  1108. //
  1109. // set up a sending ECB
  1110. //
  1111.   memset (&IPX_packets[0],0,sizeof(IPX_packets[0]));
  1112.  
  1113.   IPX_packets[0].ecb.Socket = IPX_socketid;
  1114.   IPX_packets[0].ecb.FragCount = 2;
  1115.   IPX_packets[0].ecb.Fragment[0].FragData = (BYTE *)&IPX_packets[0].ipx;
  1116.   IPX_packets[0].ecb.Fragment[1].FragData = (BYTE *)&doomcom->data;
  1117.   memcpy (IPX_packets[0].ipx.Dst.Network, IPX_localadr.network, 4);
  1118.   IPX_packets[0].ipx.Dst.Socket = IPX_socketid;
  1119.  
  1120.   /* why doesn't amipx.library fill in ipx.Src? */
  1121.   memcpy (&IPX_packets[0].ipx.Src, &IPX_localadr, 4 + 6);
  1122.   IPX_packets[0].ipx.Src.Socket = IPX_socketid;
  1123.  
  1124. // known local node at 0
  1125.   memcpy (IPX_nodeadr[0].node, IPX_localadr.node, 6);
  1126.  
  1127. // broadcast node at MAXNETNODES
  1128.   memset (IPX_nodeadr[MAXNETNODES].node, 0xff, 6);
  1129.  
  1130.   netsend = IPX_PacketSend;
  1131.   netget = IPX_PacketGet;
  1132.   netgame = true;
  1133.  
  1134.   // parse player number and host list
  1135.  
  1136.   IPX_LookForNodes (myargv[p+1][0] - '0');
  1137.  
  1138.   IPX_localtime = 0;
  1139.  
  1140.   doomcom->id = DOOMCOM_ID;
  1141. }
  1142.  
  1143. /**********************************************************************/
  1144. static void IPX_Shutdown (void)
  1145. {
  1146.   if (IPX_socketid != 0) {
  1147.     printf ("IPX_Shutdown: Closing socket and library\n");
  1148.     AMIPX_CloseSocket (IPX_socketid);
  1149.     IPX_socketid = 0;
  1150.   }
  1151.   if (AMIPX_Library != NULL) {
  1152.     CloseLibrary ((struct Library *)AMIPX_Library);
  1153.     AMIPX_Library = NULL;
  1154.   }
  1155. }
  1156.  
  1157. /**********************************************************************/
  1158.  
  1159. #endif  /* IPX */
  1160.  
  1161. /**********************************************************************/
  1162. /**********************************************************************/
  1163. //
  1164. // I_InitNetwork
  1165. //
  1166. void I_InitNetwork (void)
  1167. {
  1168.   int i;
  1169.   int p;
  1170.  
  1171.     atexit(cleanup_net);
  1172.  
  1173.   doomcom = malloc (sizeof (*doomcom) );
  1174.   memset (doomcom, 0, sizeof(*doomcom) );
  1175.  
  1176.   // set up for network
  1177.   i = M_CheckParm ("-dup");
  1178.   if (i && i < myargc - 1) {
  1179.     doomcom->ticdup = myargv[i+1][0]-'0';
  1180.     if (doomcom->ticdup < 1)
  1181.       doomcom->ticdup = 1;
  1182.     if (doomcom->ticdup > 9)
  1183.       doomcom->ticdup = 9;
  1184.   } else
  1185.     doomcom-> ticdup = 1;
  1186.  
  1187.   if (M_CheckParm ("-extratic"))
  1188.     doomcom-> extratics = 1;
  1189.   else
  1190.     doomcom-> extratics = 0;
  1191.  
  1192.   p = M_CheckParm ("-port");
  1193.   if (p && p < myargc - 1) {
  1194.     IP_DOOMPORT = atoi (myargv[p+1]);
  1195.     printf ("using alternate port %i\n",IP_DOOMPORT);
  1196.   }
  1197.  
  1198.   // parse network game options,
  1199.   //  -net <consoleplayer> <host> <host> ...
  1200.   if ((i = M_CheckParm ("-net")) != 0) {
  1201.  
  1202.     IP_InitNetwork (i);
  1203.  
  1204.   } else if ((i = M_CheckParm ("-netserial")) != 0) {
  1205.  
  1206.     SER_InitNetwork (i);
  1207.  
  1208. #ifdef AMIPX
  1209.  
  1210.   } else if ((i = M_CheckParm ("-netipx")) != 0) {
  1211.  
  1212.     IPX_InitNetwork (i);
  1213.  
  1214. #endif
  1215.  
  1216.   } else {
  1217.  
  1218.     // single player game
  1219.     netgame = false;
  1220.     doomcom->id = DOOMCOM_ID;
  1221.     doomcom->numplayers = doomcom->numnodes = 1;
  1222.     doomcom->deathmatch = false;
  1223.     doomcom->consoleplayer = 0;
  1224.  
  1225.   }
  1226. }
  1227.  
  1228.  
  1229. /**********************************************************************/
  1230. void I_NetCmd (void)
  1231. {
  1232.   if (doomcom->command == CMD_SEND) {
  1233. #ifdef AMIPX
  1234.     IPX_localtime++;
  1235. #endif
  1236.     netsend ();
  1237.   } else if (doomcom->command == CMD_GET) {
  1238.     netget ();
  1239.   } else
  1240.     I_Error ("Bad net cmd: %i\n",doomcom->command);
  1241. }
  1242.  
  1243. /**********************************************************************/
  1244. void cleanup_net (void)
  1245. {
  1246.   IP_Shutdown ();
  1247.   SER_Shutdown ();
  1248. #ifdef AMIPX
  1249.   IPX_Shutdown ();
  1250. #endif
  1251. }
  1252.  
  1253. /**********************************************************************/
  1254.